package com.lmabbe.common.datasources.interceptor;

import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.lmabbe.common.datasources.core.LmabbeWrapper;
import com.lmabbe.common.global.context.LmabbeSessionUser;
import com.lmabbe.common.global.context.session.LoginUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.context.ApplicationContext;

import java.sql.SQLException;
import java.util.stream.Collectors;

/**
 * 数据权限拦截器
 *
 * @author lmabbe
 */
@Slf4j
@RequiredArgsConstructor
public class DataScopeInterceptor implements InnerInterceptor {

    private final ApplicationContext applicationContext;

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        LmabbeSessionUser sessionUser = applicationContext.getBean(LmabbeSessionUser.class);
        if (null == sessionUser || null == sessionUser.loginUser()) {
            log.debug("用户尚未登录，在执行系统sql");
            return;
        }
        boolean ignoreDataScope = ignoreDataScope(ms, parameter);
        if (ignoreDataScope) {
            log.debug("忽略执行数据权限");
            return;
        }
        LoginUser loginUser = sessionUser.loginUser();
        String sql = null;
        switch (loginUser.getDataScope()) {
            case SELF:
                sql = "select data_scope_temp.* from (" + boundSql.getSql() + ") as data_scope_temp where data_scope_temp.create_by = " + loginUser.getUserId();
                break;
            case CUSTOMIZE:
                String collect = loginUser.getCustomDataScope()
                        .parallelStream()
                        .map(Object::toString)
                        .collect(Collectors.joining(","));
                sql = "select data_scope_temp.* from (" + boundSql.getSql() + ") as data_scope_temp where data_scope_temp.org_id in (" + collect + ")";
                break;
            case THIS_LEVEL:
                sql = "select data_scope_temp.* from (" + boundSql.getSql() + ") as data_scope_temp where data_scope_temp.org_id = " + loginUser.getCustomDataScope().get(0);
                break;
            case THIS_LEVEL_CHILDREN:
                sql = "select data_scope_temp.* from (" + boundSql.getSql() + ") as data_scope_temp inner join sys_org so on so.org_id = data_scope_temp.org_id" +
                        " where so.valid = 1 and JSON_CONTAINS(so.tree_path,\"" + loginUser.getCustomDataScope().get(0) + "\")";
                break;
            case UNKNOWN:
                throw new RuntimeException("用户权限异常，请赋予用户权限");
        }
        if (sql != null) {
            PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
            mpBoundSql.sql(sql);
        }

    }

    private boolean ignoreDataScope(MappedStatement ms, Object parameter) {
        boolean dataScope = InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.getId(), "dataScope");
        if (dataScope) {
            return true;
        }
        if (parameter instanceof MapperMethod.ParamMap) {
            MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameter;
            if (paramMap.containsKey("ew") && paramMap.get("ew") instanceof LmabbeWrapper) {
                LmabbeWrapper wrapper = (LmabbeWrapper) paramMap.get("ew");
                return wrapper.isIgnoreDataScope();
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
}
